/**
 * 
 */
package com.nanosheep.freewheel.util;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.andnav.osm.util.BoundingBoxE6;
import org.andnav.osm.util.GeoPoint;
import org.andnav.osm.views.OpenStreetMapView;
import org.andnav.osm.views.overlay.OpenStreetMapViewOverlayItem;
import org.andnav.osm.views.util.constants.MathConstants;

import com.nanosheep.accessmap.R;
import com.nanosheep.freewheel.parser.OSMParser;

import android.content.Context;
import android.graphics.Point;
import android.graphics.drawable.Drawable;

/**
 * @author jono@nanosheep.net
 * @version Nov 8, 2010
 */
public final class Markers {

	private static final int EARTH_RADIUS = 3960;
	/** Pi/180 for converting degrees - radians. **/
	public static final double PI_180 = Math.PI / 180;
	
	/**
	 * Get markers from the api.
	 * 
	 * @param p Center point
	 * @param mv radius to collect markers within.
	 * @return an arraylist of OverlayItems corresponding to markers in range.
	 */

	public static List<OpenStreetMapViewOverlayItem> getMarkers(final GeoPoint p,
			final OpenStreetMapView mv, final Context mAct, String[] opts) {
		final String sep = URLEncoder.encode("|");
		String query = mAct.getString(R.string.access_api) + 
		URLEncoder.encode(mAct.getString(R.string.node_start)) + "=";
		for (int i = 0; i < opts.length; i++) {
			query += opts[i];
			query = i + 1 < opts.length ? query + sep : query;
		}
		query += URLEncoder.encode(mAct.getString(R.string.node_end)) + getOSMBounds(mv);
		final List<OpenStreetMapViewOverlayItem> markers = new ArrayList<OpenStreetMapViewOverlayItem>();
		final OSMParser parser = new OSMParser(query);
		final Point hotspot = new Point(0, 20);
		final Drawable markerIcon = mAct.getResources().getDrawable(R.drawable.icon);

		// Parse XML to overlayitemsn p
		for (GeoPoint point : parser.parse()) {
			OpenStreetMapViewOverlayItem marker = new OpenStreetMapViewOverlayItem("", "", point);
			marker.setMarker(markerIcon);
			marker.setMarkerHotspot(hotspot);
			markers.add(marker);
		}

		return markers;
	}

	/**
	 * Generate an array of points representing a MBR for the circle described
	 * by the radius given.
	 * 
	 * @param p point to use as center
	 * @param distance radius to bound within.
	 * @return an array of 4 geopoints representing an mbr drawn clockwise from the ne corner.
	 */
	private static List<GeoPoint> getBounds(final GeoPoint p, final double distance) {
		final List<GeoPoint> points = new ArrayList<GeoPoint>(4);
		final int degrees = Convert.asMicroDegrees(((distance / EARTH_RADIUS) 
				* (1/PI_180)));
		final double latRadius = EARTH_RADIUS * Math.cos(degrees * PI_180);
		final int degreesLng = Convert.asMicroDegrees( (distance / latRadius) * (1/PI_180));

		final int maxLng = degreesLng + p.getLongitudeE6();
		final int maxLat = degrees + p.getLatitudeE6();

		final int minLng = p.getLongitudeE6() - degreesLng;
		final int minLat = p.getLatitudeE6() - degrees;

		points.add(new GeoPoint(maxLat, maxLng));
		points.add(new GeoPoint(maxLat, minLng));
		points.add(new GeoPoint(minLat, minLng));
		points.add(new GeoPoint(minLat, maxLng));

		return points;
	}
	
	/**
	 * Get an OSM bounding box string of an array of GeoPoints representing
	 * a bounding box drawn clockwise from the northeast.
	 * @param mv List of geopoints
	 * @return a string in OSM xapi bounding box form.
	 */
	
	
	private static String getOSMBounds(final OpenStreetMapView mv) {
		BoundingBoxE6 bb = mv.getVisibleBoundingBoxE6();
		final StringBuffer sBuf = new StringBuffer("%5Bbbox=");
		sBuf.append(Convert.asDegrees(bb.getLonWestE6()));
		sBuf.append(',');
		sBuf.append(Convert.asDegrees(bb.getLatSouthE6()));
		sBuf.append(',');
		sBuf.append(Convert.asDegrees(bb.getLonEastE6()));
		sBuf.append(',');
		sBuf.append(Convert.asDegrees(bb.getLatNorthE6()));
		sBuf.append("%5D");

		return sBuf.toString();
	}
}
